package server;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;


/**
 * Minicat的主类
 */
public class Bootstrap {

    /**定义socket监听的端口号*/
    private int port = 8080;
    private String appBase = "";

    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }

    private Map<String,HttpServlet> webServletMap = new HashMap<String,HttpServlet>();
    List<Context> contexts = new ArrayList<>();

    /**
     * Minicat启动需要初始化展开的一些操作
     */
    public void start() throws Exception {

        //加载 server.xml
        loadServer();
        //遍历 server中配置的部署单元
        for (Context context : contexts) {
            // 加载解析相关的配置，web.xml
            loadServlet(webServletMap,context);
        }

        // 定义一个线程池
        int corePoolSize = 10;
        int maximumPoolSize =50;
        long keepAliveTime = 100L;
        TimeUnit unit = TimeUnit.SECONDS;
        BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(50);
        ThreadFactory threadFactory = Executors.defaultThreadFactory();
        RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();


        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                corePoolSize,
                maximumPoolSize,
                keepAliveTime,
                unit,
                workQueue,
                threadFactory,
                handler
        );


        ServerSocket webServerSocket = new ServerSocket(port);
        System.out.println("=====>>>Minicat start on port：" + port);

        System.out.println("=========>>>>>>使用线程池进行多线程改造");
        /*
            多线程改造（使用线程池）
         */
        while(true) {

            //启动外部包里面的web.xml
            Socket webSocket = webServerSocket.accept();
            RequestProcessor webRequestProcessor = new RequestProcessor(webSocket,webServletMap,appBase,contexts);
            webRequestProcessor.start();
            threadPoolExecutor.execute(webRequestProcessor);

        }

    }

    /**
     * 加载解析web.xml，初始化Servlet
     */
    private void loadServlet(Map<String,HttpServlet> servletMap,Context context) {
        SAXReader saxReader = new SAXReader();
        String base = appBase+context.getDocBase();
        System.out.println("loadServlet====   "+base);

        try {
            InputStream resourceAsStream = new FileInputStream(base+"\\web.xml");
            Document document = saxReader.read(resourceAsStream);
            Element rootElement = document.getRootElement();

            List<Element> selectNodes = rootElement.selectNodes("//servlet");
            for (int i = 0; i < selectNodes.size(); i++) {
                Element element =  selectNodes.get(i);
                // <servlet-name>lagou</servlet-name>
                Element servletnameElement = (Element) element.selectSingleNode("servlet-name");
                String servletName = servletnameElement.getStringValue();
                // <servlet-class>server.LagouServlet</servlet-class>
                Element servletclassElement = (Element) element.selectSingleNode("servlet-class");
                String servletClass = servletclassElement.getStringValue();


                // 根据servlet-name的值找到url-pattern
                Element servletMapping = (Element) rootElement.selectSingleNode("/web-app/servlet-mapping[servlet-name='" + servletName + "']");
                // /lagou
                String urlPattern = servletMapping.selectSingleNode("url-pattern").getStringValue();
                File file = new File(base);
                URL url = file.toURI().toURL();
                URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{url});
                //通过urlClassLoader加载器调用loadClass方法传入类名动态加载class文件并获取class对象
                Class<?> classs = urlClassLoader.loadClass(servletClass);
                //通过class对象创建实例
                HttpServlet servlet = (HttpServlet) classs.newInstance();
                System.out.println(servlet);
                servletMap.put(context.getPath()+urlPattern, servlet);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }


    private void loadServer(){
        InputStream serverStream = this.getClass().getClassLoader().getResourceAsStream("server.xml");
        SAXReader saxReader = new SAXReader();
        try{
            Document read = saxReader.read(serverStream);
            Element rootElement = read.getRootElement();
            Element conClement = (Element) rootElement.selectSingleNode("//Connector");
            port = Integer.parseInt(conClement.attributeValue("port"));
            System.out.println("======"+port);
            Element hostElement = (Element) rootElement.selectSingleNode("//Host");
            appBase = hostElement.attributeValue("appBase");
            System.out.println("======"+appBase);
            List<Element> listContext = read.selectNodes("//Context");
            for (Element element : listContext) {
                String docBase = element.attributeValue("docBase");
                String path = element.attributeValue("path");
                System.out.println(docBase+"======"+path);
                Context context = new Context(docBase,path);
                contexts.add(context);
            }
        }catch(Exception e){

        }

    }

    /**
     * Minicat 的程序启动入口
     * @param args
     */
    public static void main(String[] args) {
        Bootstrap bootstrap = new Bootstrap();
        try {
            // 启动Minicat
            bootstrap.start();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}
/*
*
*
        while(true) {
            Socket socket = serverSocket.accept();
            // 有了socket，接收到请求，获取输出流
            OutputStream outputStream = socket.getOutputStream();
            String data = "Hello Minicat!";
            String responseText = HttpProtocolUtil.getHttpHeader200(data.getBytes().length) + data;
            outputStream.write(responseText.getBytes());
            socket.close();
        }



        *//**
 * 完成Minicat 2.0版本
 * 需求：封装Request和Response对象，返回html静态资源文件
 *//*
 *//*  while(true) {
            Socket socket = serverSocket.accept();
            InputStream inputStream = socket.getInputStream();

            int count = 0;
            while(count == 0 ){
                count = inputStream.available();
            }
            byte [] bytes = new byte[count];
            inputStream.read(bytes);
            System.out.println("==========>请求信息："+new String(bytes));
        }

        while(true) {
            Socket socket = serverSocket.accept();
            InputStream inputStream = socket.getInputStream();

            // 封装Request对象和Response对象
            Request request = new Request(inputStream);
            Response response = new Response(socket.getOutputStream());

            response.outputHtml(request.getUrl());
            socket.close();

        }


        *//**
 * 完成Minicat 3.0版本
 * 需求：可以请求动态资源（Servlet）
 *//*
 *//*while(true) {
            Socket socket = serverSocket.accept();
            InputStream inputStream = socket.getInputStream();

            // 封装Request对象和Response对象
            Request request = new Request(inputStream);
            Response response = new Response(socket.getOutputStream());

            // 静态资源处理
            if(servletMap.get(request.getUrl()) == null) {
                response.outputHtml(request.getUrl());
            }else{
                // 动态资源servlet请求
                HttpServlet httpServlet = servletMap.get(request.getUrl());
                httpServlet.service(request,response);
            }

            socket.close();

        }


        *//*
            多线程改造（不使用线程池）
         *//*
 *//*while(true) {
            Socket socket = serverSocket.accept();
            RequestProcessor requestProcessor = new RequestProcessor(socket,servletMap);
            requestProcessor.start();
        }
//            Socket socket = webServerSocket.accept();
//            InputStream inputStream = socket.getInputStream();
//
//            // 封装Request对象和Response对象
//            Request request = new Request(inputStream);
//            Response response = new Response(socket.getOutputStream());
//
//
//            // 静态资源处理
//            if(webServletMap.get(request.getUrl()) == null) {
//                response.outputHtml(appBase,request.getUrl(),getDocBase(request.getUrl()));
//            }else{
//                // 动态资源servlet请求
//                HttpServlet httpServlet = webServletMap.get(request.getUrl());
//                httpServlet.service(request,response);
//            }

*
*
* */